package cn.edu.hnu.matching.manager;

import cn.edu.hnu.matching.common.ResultCode;
import cn.edu.hnu.matching.constants.RedisConstants;
import cn.edu.hnu.matching.constants.UserConstants;
import cn.edu.hnu.matching.exception.ThrowUtils;
import cn.edu.hnu.matching.mapper.UserMapper;
import cn.edu.hnu.matching.model.entity.User;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RRateLimiter;
import org.redisson.api.RateIntervalUnit;
import org.redisson.api.RateType;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Redisson 方法管理器
 */
@Component
@RequiredArgsConstructor
public class RedissonManager {

    private final RedissonClient redissonClient;

    private final UserMapper userMapper;

    /**
     * 限流操作，按照整体速率限流
     * @param key 区分不同的限流器，比如不同用户 id 应该分别统计
     * @param rate 产生令牌数，即在单位时间内产生多少个令牌
     * @param rateInterval 单位时间时间间隔
     * @param unit 单位时间单位
     * @param permits 每次操作的时候拿取多少个令牌
     */
    public void doRateLimitsOverall(String key,
                                    long rate, long rateInterval, RateIntervalUnit unit,
                                    long permits) {
        // 通过key来创建限流器
        RRateLimiter rateLimiter = redissonClient.getRateLimiter(key);
        // OVERALL是按整体速率来限流，2代表令牌数，1 SECONDS是单位时间间隔
        rateLimiter.trySetRate(RateType.OVERALL, rate, rateInterval, unit);
        // 每当一个操作的时候，请求1个令牌
        boolean result = rateLimiter.tryAcquire(permits);
        ThrowUtils.throwIf(!result, ResultCode.REQUESTS_TOO_FREQUENT);
    }

    /**
     * 初始化用户对象信息缓存池
     */
    public void cacheUserRecommendPool() {
        // 获取分布式锁
        RLock lock = redissonClient.getLock(RedisConstants.LOCK_KEY);

        boolean isLocked = false;

        try {
            isLocked = lock.tryLock(0, 30, TimeUnit.SECONDS);

            if (isLocked) {
                // 随机抽 100 个用户出来
                List<User> users = userMapper.selectList(new LambdaQueryWrapper<User>()
                        .select(User::getId, User::getTags, User::getOpenId)
                        .eq(User::getIsDelete, UserConstants.UN_DELETED)
                        .last("ORDER BY RAND() LIMIT " + 100));

                // 放入缓存中
                redissonClient.getBucket(RedisConstants.CACHE_KEY).set(users);
            }

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 最后需要释放掉这个锁
            if (isLocked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 获取用户对象信息缓存池
     * @return 用户对象信息列表
     */
    public List<User> getUserRecommendPool() {
        RBucket<List<User>> bucket = redissonClient.getBucket(RedisConstants.CACHE_KEY);
        return bucket.get();
    }

}
